package org.javaexpert.junit4;

import org.junit.runner.Description;
import org.junit.runner.manipulation.Filter;

import java.util.*;

/**
 * Created by IntelliJ IDEA.
 * User: piotrga
 * Date: Mar 19, 2008
 * Time: 9:32:40 PM
 * To change this template use File | Settings | File Templates.
 */
public class MethodFilter extends Filter{
    Set<String> includeGroups;
    Set<String> excludeGroups;
    private Set<String> classLevelGroupsPresent;

    public MethodFilter(Set<String> includeGroups, Set<String> excludeGroups, Set<String> classLevelGroupsPresent) {
        this.includeGroups = includeGroups;
        this.excludeGroups = excludeGroups;
        this.classLevelGroupsPresent = classLevelGroupsPresent;
        if (includeGroups == null) {
            this.includeGroups = new HashSet<String>();
            this.includeGroups.add("all");
        }
        if (excludeGroups == null) this.excludeGroups = Collections.EMPTY_SET;
        if (classLevelGroupsPresent == null) this.classLevelGroupsPresent = Collections.EMPTY_SET;

    }

    public boolean shouldRun(Description description) {
        return includes(description) && !excludes(description);
    }

    private boolean excludes(Description description) {
        return haveCommonElements(presentGroups(description), excludeGroups);

    }

    private List<String> presentGroups(Description description) {
        List<String> res = new ArrayList(classLevelGroupsPresent);
        TestGroups annotation = description.getAnnotation(TestGroups.class);
        if (annotation != null) res.addAll(Arrays.asList(annotation.value()));
        return res;
    }

    private boolean includes(Description description) {
        if (includeGroups.contains("all")) return true;
        return haveCommonElements(presentGroups(description), includeGroups);
    }

    private boolean haveCommonElements(Collection<String> collection1, Collection<String> collection2) {
        return !Collections.disjoint(collection1, collection2);
    }

    public String describe() {
        return String.format("Filter includes(%s), excludes(%s)", includeGroups, excludeGroups);
    }
}
